#include <execinfo.h>
#include <dlfcn.h>
#include <cxxabi.h>
#include <stdio.h>

#define BACKTRACE_MAXDEPTH 32

struct layout {
   struct layout *__unbounded next;
   void *__unbounded sp;
   void *__unbounded return_address;
};

int __arm_backtrace( int **arr, int maxsiz )
{
    int cnt = 0;
    void *fp = __builtin_frame_address( 0 );
    struct layout *lp = (struct layout *)((char*)fp - 12);
    while ( cnt < maxsiz ) {
//        printf("lp[%d]: %p ra: %p next: %p\n", cnt, (void *)lp, (void *)lp->return_address, (void *)lp->next);
        arr[cnt++] = (int *)lp->return_address;
        if (!lp->next) {
            break;
        }
        lp = lp->next - 1;
    }
    return cnt;
}

inline void __printBacktrace( int skipCount )
{
    int * func_addresses[ BACKTRACE_MAXDEPTH ];
    char demangle_output[ 1000 ];
//    int nfuncs = backtrace( func_addresses, BACKTRACE_MAXDEPTH );
    int nfuncs = __arm_backtrace( func_addresses, BACKTRACE_MAXDEPTH );
    for ( int i = skipCount; i < nfuncs; ++i ) {
        Dl_info info;
        if ( dladdr( func_addresses[i], &info ) ) {
            int dStat;
            size_t dLength = 1000;
            char * demangled = abi::__cxa_demangle(info.dli_sname, demangle_output, &dLength, &dStat);
            if ( demangled && !dStat )
                fprintf(stderr, "return addr: %p: object:%s %p symbol:%s [%p+0x%x]\n", func_addresses[i], info.dli_fname, info.dli_fbase, demangled, info.dli_saddr, (int)func_addresses[i] - (int)info.dli_saddr);
            else
                fprintf(stderr, "return addr: %p: object:%s %p symbol:%s [%p+0x%x]\n", func_addresses[i], info.dli_fname, info.dli_fbase, info.dli_sname, info.dli_saddr, (int)func_addresses[i] - (int)info.dli_saddr);
        } else
            fprintf(stderr, "return addr: %p\n", func_addresses[i]);
    }
}
